import dayjs from 'dayjs'
import { ContentType } from '../enums/request.enum'
import { ExceptionFilter, Catch, ArgumentsHost, HttpStatus, Logger } from '@nestjs/common'
import { TimeFormat } from '../enums/time-format.enum'

/**
 * 全局异常过滤器：统一处理应用中所有未捕获的异常
 * 实现对不同类型异常的标准化响应，确保客户端获得一致的错误格式
 */
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  private logger = new Logger(AllExceptionsFilter.name)

  /**
   * 异常捕获与处理的核心方法
   * @param exception 捕获到的异常实例
   * @param host 上下文对象，用于获取请求/响应对象
   */
  catch(exception: any, host: ArgumentsHost) {
    // 切换到 HTTP 上下文，获取 Express 风格的请求和响应对象
    const context = host.switchToHttp()
    const request = context.getRequest<ExpressRequest>()
    const response = context.getResponse<ExpressResponse>()

    // 初始化异常响应字段
    let status: number = exception.status ?? HttpStatus.INTERNAL_SERVER_ERROR // HTTP 状态码
    let code: number = exception.status ?? HttpStatus.INTERNAL_SERVER_ERROR // 业务错误码
    let message = exception.message ?? exception // 错误提示信息

    // 处理自定义 ApiException 异常
    if (exception.name === 'ApiException') {
      status = HttpStatus.OK // 自定义异常通常返回 200，通过 code 区分业务错误
      code = exception.code // 使用异常中定义的业务错误码
    }

    // 处理 NestJS 内置 HttpException 及其子类
    if (exception.name === 'HttpException') {
      code = exception.status // 复用 HTTP 状态码作为业务错误码
    }

    // 处理数据验证异常（DTO 管道校验失败）
    if (exception.name === 'BadRequestException') {
      code = exception.status
      // 提取验证错误信息（class-validator 可能返回数组）
      message = Array.isArray(exception.response.message) ? exception.response.message[0] : exception.response.message
    }

    // 处理请求频率限制异常（Throttler 模块）
    if (exception.name === 'ThrottlerException' || message.includes('status code 429')) {
      code = HttpStatus.TOO_MANY_REQUESTS
      message = '您的操作过于频繁，请稍后再试' // 标准化提示信息
    }

    // NotFoundException 处理资源未找到异常
    if (exception.name === 'NotFoundException') {
      if (exception.message.includes('favicon.ico')) return // 忽略浏览器对 favicon.ico 的默认请求异常
      message = '请求的资源未找到，请确认 URL 是否正确'
    }

    // 数据库连接异常
    if (exception.code === 'ECONNRESET' && exception.driverError) {
      message = '数据库连接异常，请联系管理员'
    }

    // 处理数据库外键约束异常
    if (message.includes('foreign key constraint fails')) {
      message = '数据库存在外键约束，导致操作失败'
    }

    // 处理未预期的未知异常（兜底处理）| 生产环境隐藏详细错误信息，避免泄露敏感信息
    // if (status === HttpStatus.INTERNAL_SERVER_ERROR && process.env.NODE_ENV === 'production') {
    //   status = HttpStatus.OK
    //   message = '服务器内部错误，请稍后重试'
    // }

    const { method, query, body, path } = request
    this.logger.error({ message, method, path, timestamp: dayjs().format(TimeFormat.DATETIME_DASH), query, body })

    response.status(status)
    response.setHeader('Content-Type', ContentType.APPLICATION_JSON)
    response.json({ code, success: false, message, data: null, timestamp: Date.now() })
  }
}
